﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

//[assembly: InternalsVisibleTo("DynamicAppDomainTests.dll", AllInternalsVisible=true)]

namespace DynamicAppDomain
{
	public static class Program
	{
		static string TryCut(ParameterInfo param, ref string[] args)
		{
			for (var i = 0; i < args.Length; i++)
			{
				var item = args[i];
				if (!item.StartsWith("-") && !item.StartsWith("/"))
				{
					return null;
				}
				item = item.Substring(1).Trim().Trim('\"');
				if (param.Names.Any(pn => string.Equals(item, pn, StringComparison.OrdinalIgnoreCase)))
				{
					var value = param.GetValue(item, ref args, i);
					args = args.Where((_, j) => j != i).ToArray();
					return value;
				}
			}
			return null;
		}

		static void Main(string[] args)
		{
			// Debugger.Launch();

			var readFromFile = TryCut(new FileNameParameterInfo("in"), ref args);
			var writeToFile = TryCut(new FileNameParameterInfo("out"), ref args);
			var references = new List<string>();
			string reference;
			while (null != (reference = TryCut(new NextParamValueParameterInfo("ref"), ref args)))
			{
				references.Add(reference);
			}

			var ce = new CodeExecutor { References = references, ImportAllNamespaces=true };
			object result;
			if(readFromFile==null)
			{
				result = ce.RunExpression(string.Join(" ", args));
			}else
			{
				result = ce.Run(File.ReadAllText(readFromFile));
			}
			if (writeToFile == null)
			{
				Console.WriteLine(result);
			}
			else
			{
				File.WriteAllText(writeToFile, result.ToString());
				Console.WriteLine("OK");
			}
		}

		#region Nested type: ExistanceParameterInfo

		class ExistanceParameterInfo : ParameterInfo
		{
			public ExistanceParameterInfo(params string[] names) : base(names) {}

			public override string GetValue(string name, ref string[] args, int i)
			{
				throw new NotImplementedException();
			}
		}

		#endregion

		#region Nested type: FileNameParameterInfo

		class FileNameParameterInfo : NextParamValueParameterInfo
		{
			public FileNameParameterInfo(params string[] names) : base(names) {}

			public override string GetValue(string name, ref string[] args, int i)
			{
				var value = base.GetValue(name, ref args, i);
				if (!File.Exists(value))
				{
					throw new Exception(string.Format("File '{0}' does not exists.", value));
				}
				return value;
			}
		}

		#endregion

		#region Nested type: NextParamValueParameterInfo

		class NextParamValueParameterInfo : ParameterInfo
		{
			public NextParamValueParameterInfo(params string[] names) : base(names) {}

			public override string GetValue(string name, ref string[] args, int i)
			{
				if (i >= args.Length - 1)
				{
					throw new Exception(string.Format("Parameter '{0}' should have a value next to them", name));
				}
				var value = args[i + 1];
				args = args.Where((_, j) => j != i + 1).ToArray();
				return value;
			}
		}

		#endregion

		#region Nested type: ParameterInfo

		abstract class ParameterInfo
		{
			readonly string[] _names;

			/// <summary>
			/// Holder of full information about parameter
			/// </summary>
			/// <param name="names">Aliaces</param>
			protected ParameterInfo(params string[] names)
			{
				_names = names;
			}

			public string[] Names
			{
				get { return _names; }
			}

			public abstract string GetValue(string name, ref string[] args, int i);
		}

		#endregion
	}

	public class TemporaryAppDomain {}
}